//
// Created by Administrator on 2021/1/30 0030.
//

#include <jni.h>
#include <string>
#include "CallJava.h"
#include "JqhFFmpeg.h"
#include "JqhPlayStatus.h"
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

extern "C"
{
#include <libavformat/avformat.h>
}

JavaVM *javaVM = NULL;
CallJava *callJava = NULL;
JqhFFmpeg *fFmpeg;
JqhPlayStatus *playStatus = NULL;
bool nexit = true;

pthread_t thread_start;

extern  "C"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    LOGD("JNI_OnLoad")
    jint result = -1;
    javaVM = vm;
    JNIEnv *env ;
    if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {
        return result;
    }
    return JNI_VERSION_1_4;
}


extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1parpared(JNIEnv *env, jobject instance, jstring source_) {
    const char *source = env->GetStringUTFChars(source_, 0);
    if (fFmpeg == NULL) {
        if (callJava == NULL) {
            callJava = new CallJava(javaVM, env, &instance);
        }
        callJava->onCallLoad(MAIN_THREAD, true);
        playStatus = new JqhPlayStatus();
        fFmpeg = new JqhFFmpeg(playStatus, callJava, source);
        fFmpeg->parpared();
    }

    env->ReleaseStringUTFChars(source_, source);
}

void *startCallBack(void *data){
    JqhFFmpeg *fFmpeg = (JqhFFmpeg *)data;
    fFmpeg->start();
    pthread_exit(&thread_start);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1start(JNIEnv *env, jobject instance) {

    if (fFmpeg != NULL) {
//        fFmpeg->start();
        pthread_create(&thread_start, NULL, startCallBack, fFmpeg);
    }

}

// 以下是测试播放pcm的代码
SLObjectItf engineObject = NULL;
SLEngineItf engineEngine = NULL;

//混音器
SLObjectItf outputMixObject = NULL;
SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;


//pcm
SLObjectItf pcmPlayerObject = NULL;
SLPlayItf pcmPlayerPlay = NULL;
SLVolumeItf pcmPlayerVolume = NULL;

//缓冲器队列接口
SLAndroidSimpleBufferQueueItf pcmBufferQueue;

FILE *pcmFile;
void *buffer;

uint8_t *out_buffer;

int getPcmData(void **pcm) {
    int size = 0 ;
    while (!feof(pcmFile)) {
        size = fread(out_buffer, 1 ,44100 *2 * 2, pcmFile);
        if (out_buffer == NULL) {
            LOGD("%s", "read end");
            break;
        } else {
            LOGD("%s", "reading");
        }
        *pcm = out_buffer;
        break;
    }
    return size;
}
void pcmBufferCallBack1(SLAndroidSimpleBufferQueueItf bf, void *context) {
    LOGD("pcmBufferCallBack...")
    int size = getPcmData(&buffer);
    if (buffer != NULL) {
        (*pcmBufferQueue)->Enqueue(pcmBufferQueue, buffer, size);
    }
}

// 测试播放pcm
extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1playpcm(JNIEnv *env, jobject instance, jstring url_) {
    const char *url = env->GetStringUTFChars(url_, 0);
    LOGD("开始打开文件 %s", url)
    // TODO
    //读取pcm文件
    pcmFile = fopen(url, "r");
    if(pcmFile == NULL)
    {
        LOGE("%s", "fopen file error");
        return;
    }
    out_buffer = (uint8_t *) malloc(44100 * 2 * 2);


    SLresult result;
    //第一步------------------------------------------
    // 创建引擎对象
    slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
    (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);


    //第二步-------------------------------------------
    // 创建混音器
    const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean mreq[1] = {SL_BOOLEAN_FALSE};
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, mids, mreq);
    (void)result;
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    (void)result;
    result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, &outputMixEnvironmentalReverb);
    if (SL_RESULT_SUCCESS == result) {
        result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                outputMixEnvironmentalReverb, &reverbSettings);
        (void)result;
    }
    SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};

    // 创建播放器
    LOGD("创建播放器")
    SLDataLocator_AndroidSimpleBufferQueue android_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};
    SLDataFormat_PCM pcm = {
            SL_DATAFORMAT_PCM,
            2,
            SL_SAMPLINGRATE_44_1,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
            SL_BYTEORDER_LITTLEENDIAN
    };

    SLDataSource slDataSource = {&android_queue, &pcm};
    LOGD("创建播放器1")
    SLDataSink audioSnk = {&outputMix, NULL};
    const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME};
    const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};

    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk, 3, ids, req);
    LOGD("创建播放器2")
    (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
    LOGD("创建播放器21")
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
    LOGD("创建播放器22")
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
    LOGD("创建播放器3")
    (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack1, NULL);
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmPlayerVolume);

    (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
    LOGD("创建播放器4")
    pcmBufferCallBack1(pcmBufferQueue, NULL);

    env->ReleaseStringUTFChars(url_, url);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1pause(JNIEnv *env, jobject instance) {

    if (fFmpeg != NULL) {
        fFmpeg->pause();
    }

}extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1resume(JNIEnv *env, jobject instance) {

    if (fFmpeg != NULL) {
        fFmpeg->resume();
    }

}extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1stop(JNIEnv *env, jobject instance) {

    // 防止多次点击stop频繁调用的问题
    if (!nexit) return;
    jclass jlz = env->GetObjectClass(instance);
    jmethodID jmid_next = env->GetMethodID(jlz, "onCallNext", "()V");
    nexit = false;
   if (fFmpeg != NULL)
   {
       fFmpeg->release();
       delete(fFmpeg);
       fFmpeg = NULL;
       if (callJava != NULL) {
           delete (callJava);
           callJava = NULL;
       }
       if (playStatus != NULL) {
           delete(playStatus);
           playStatus = NULL;
       }

   }
   nexit = true;
    env->CallVoidMethod(instance, jmid_next);

}extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1seek(JNIEnv *env, jobject instance, jint secds) {

    if (fFmpeg != NULL) {
        fFmpeg->seek(secds);
    }

}extern "C"
JNIEXPORT jint JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1duration(JNIEnv *env, jobject instance) {

    if (fFmpeg != NULL) {
        return fFmpeg->duration;
    }
}extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1volume(JNIEnv *env, jobject instance, jint percent) {

    if (fFmpeg != NULL) {
        return fFmpeg->setVolume(percent);
    }

}extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1setMute(JNIEnv *env, jobject instance, jint mute) {

    if (fFmpeg != NULL) {
        return fFmpeg->setMute(mute);
    }

}extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1speed(JNIEnv *env, jobject instance, jfloat speed) {
    if (fFmpeg != NULL) {
        return fFmpeg->setSpeed(speed);
    }

}extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1pitch(JNIEnv *env, jobject instance, jfloat pitch) {
    if (fFmpeg != NULL) {
        return fFmpeg->setPitch(pitch);
    }
}extern "C"
JNIEXPORT jint JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1samolerate(JNIEnv *env, jobject instance) {

    if (fFmpeg != NULL) {
        return fFmpeg->getSampleRate();
    }
    return 0;

}extern "C"
JNIEXPORT void JNICALL
Java_com_jqh_myplayer_player_JqhPlayer_n_1startstoprecord(JNIEnv *env, jobject instance,
                                                          jboolean start) {

    if (fFmpeg != NULL) {
        return fFmpeg->startStopRecord(start);
    }

}